﻿using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using EnvDTE;
using EnvDTE80;

namespace AzurePlugin
{
    class BackupCreator
    {
        private DTE2 application { get; set; }

        public BackupCreator(DTE2 application)
        {
            this.application = application;
        }

        public void DoBackup(string backupFolder, IEnumerable<Project> projects)
        {
            if (!application.Solution.IsOpen)
                throw new ArgumentException("application.Solution is not opened");


            if (application.Solution.FileName == null)
                throw new ArgumentNullException("application.Solution.FileName is null");

            string solutionFile = application.Solution.FileName;
            string solutionFolder = Path.GetDirectoryName(solutionFile);

            Directory.CreateDirectory(backupFolder);

            // copy solution file
            File.Copy(solutionFile, Path.Combine(backupFolder, Path.GetFileName(solutionFile)));

            foreach (Project project in projects)
            {
                string projectPath = project.FullName;

                if (String.IsNullOrEmpty(projectPath))
                    continue;

                string projectFolder = Path.GetDirectoryName(Path.Combine(solutionFolder, projectPath));
                string folderName = Directory.GetParent(projectPath).Name;
                string backupProjectFolder;

                // detect if this project is external.
                if (projectFolder.Contains(solutionFolder))
                {
                    string relativePart = projectFolder.Substring(solutionFolder.Length + 1);
                    backupProjectFolder = Path.Combine(backupFolder, relativePart);
                }
                else
                {
                    backupProjectFolder = Path.Combine(backupFolder, project.UniqueName);
                }

                if (Directory.Exists(backupProjectFolder))
                {
                    backupProjectFolder = Path.Combine(backupFolder,
                                                       folderName + "_" + Guid.NewGuid().ToString("D"));
                }

                // exit if a project file does not exist
                if (!File.Exists(projectPath))
                    continue;

                Directory.CreateDirectory(backupProjectFolder);
                File.Copy(projectPath, Path.Combine(backupProjectFolder, Path.GetFileName(projectPath)));

                backupProjectsItems(project.ProjectItems, projectFolder, backupProjectFolder);
            }
        }

        private static void backupProjectsItems(ProjectItems items, string projectFolder, string backupProjectFolder)
        {
            foreach (ProjectItem item in items)
            {
                for (short i = 0; i < item.FileCount; i++)
                {
                    string filePath = item.FileNames[i];
                    string fileFullPath = Path.Combine(projectFolder, filePath);
                    bool isDirectory = Directory.Exists(fileFullPath);
                    bool isFile = File.Exists(fileFullPath);

                    string fileBackupPath;

                    if (!isDirectory && !isFile)
                        continue;

                    // check is file is external
                    if (fileFullPath.Contains(projectFolder))
                    {
                        string relativePart = fileFullPath.Substring(projectFolder.Length + 1);
                        fileBackupPath = Path.Combine(backupProjectFolder, relativePart);
                    }
                    else
                    {
                        int lastIndex = filePath.LastIndexOf(Path.PathSeparator);
                        string fileName = lastIndex < 0 ? filePath : filePath.Substring(lastIndex + 1);
                        fileBackupPath = Path.Combine(backupProjectFolder, fileName);

                        // if file with this name is already exists in backup
                        if (isDirectory && Directory.Exists(fileBackupPath) ||
                            isFile && File.Exists(fileBackupPath))
                        {
                            fileBackupPath = Path.Combine(backupProjectFolder,
                                                          fileName + "_" + Guid.NewGuid().ToString("D"));
                        }
                    }

                    if (isFile)
                        File.Copy(fileFullPath, fileBackupPath);
                    else if(isDirectory)
                        Directory.CreateDirectory(fileBackupPath);

                    if (item.ProjectItems != null && item.ProjectItems.Count > 0)
                        backupProjectsItems(item.ProjectItems, projectFolder, backupProjectFolder);
                }
            }
        }
    }
}
